package com.sunkyc.framework.aop.login;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.sunkyc.commons.entity.R;
import com.sunkyc.framework.mq.loginmq.DisruptorMqService;
import com.sunkyc.framework.system.entity.LoginUser;
import com.sunkyc.framework.system.entity.SysLoginLog;
import com.sunkyc.framework.utils.IpUtils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Objects;

@Aspect
@Component
public class LoginAspect {

    static final Logger log = LoggerFactory.getLogger(LoginAspect.class);


    @Pointcut("@annotation(com.sunkyc.commons.annotation.LogRecord)")
    public void annotationAspect() {
    }


    @AfterReturning(pointcut = "annotationAspect()", returning = "obj")
    public void doAfter(JoinPoint joinPoint, Object obj) throws Throwable {
        setLog(joinPoint, obj, null);
    }


    @AfterThrowing(pointcut = "annotationAspect()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        Object[] args = joinPoint.getArgs();
        LoginUser loginUser = null;
        for (Object arg : args) {
            if (arg instanceof LoginUser) {
                loginUser = (LoginUser) arg;
            }
        }
        if (ObjectUtil.isNotNull(loginUser)) {
            log.info("登录用户名：{}", loginUser.getUserName());
        }
        log.error(e.getMessage());
        setLog(joinPoint,null,e);
    }


    private void setLog(JoinPoint joinPoint, Object obj, Throwable e) {
        Object[] args = joinPoint.getArgs();
        LoginUser loginUser = null;
        for (Object arg : args) {
            if (arg instanceof LoginUser) {
                loginUser = (LoginUser) arg;
            }
        }
        R r = null;
        if (obj instanceof R) {
            r = (R) obj;
        }

        SysLoginLog loginLog = null;
        if (ObjectUtil.isNotNull(r)) {
            if (ObjectUtil.isNotNull(loginUser)) {
                log.info("登录用户名：{}", loginUser.getUserName());
            }
            log.info("登录结果：{}", r.getMsg());
            loginLog = buildLog(joinPoint);
            loginLog.setLoginState("0");
            loginLog.setLoginUsername(loginUser.getUserName());
            loginLog.setLoginResult(r.getMsg());
        }

        if(ObjectUtil.isNotNull(e)){
            if (ObjectUtil.isNotNull(loginUser)) {
                log.info("登录用户名：{}", loginUser.getUserName());
            }
            log.info("登录结果：{}", e.getMessage());
            loginLog = buildLog(joinPoint);
            loginLog.setLoginState("1");
            loginLog.setLoginUsername(loginUser.getUserName());
            loginLog.setLoginResult(e.getMessage());
        }
        DisruptorMqService disruptorMqService = SpringUtil.getBean(DisruptorMqService.class);
        disruptorMqService.sendMessage(JSONUtil.toJsonStr(loginLog));
    }


    private SysLoginLog buildLog(JoinPoint joinPoint) {
        // 获取登录参数
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // ip地点
        String place = IpUtils.getIpAddress(request);
        // 地址
        String address = IpUtils.getIpSource(place);
        // 当前登入用户
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        Browser browser = userAgent.getBrowser();
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setLogId(IdUtil.getSnowflakeNextIdStr())
                .setBrowerName(browser.getName())
                .setSystemName(operatingSystem.getName())
                .setIpAddr(place)
                .setIpSources(address)
                .setLoginTime(LocalDateTime.now());
        return loginLog;

    }

}
